package com.xiaoming.plugin.tcp;

import com.alibaba.fastjson.JSONObject;
import com.xiaoming.plugin.tcp.utils.BadRequestException;
import com.xiaoming.plugin.tcp.utils.HexUtil;
import com.xiaoming.plugin.tcp.utils.Params;
import com.xiaoming.plugin.tcp.utils.Res;

import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.List;

import io.dcloud.feature.uniapp.annotation.UniJSMethod;
import io.dcloud.feature.uniapp.bridge.UniJSCallback;
import io.dcloud.feature.uniapp.common.UniModule;

public class TcpModule extends UniModule {

    String SERVER_HOST = "";
    int SERVER_PORT = 0;
    Socket socket = null;

    BufferedWriter writer = null;
    OutputStream outputStream = null;
    DataInputStream reader = null;
    public UniJSCallback _callback = null;
    public String hexMsg = "";

    @UniJSMethod(uiThread = true)
    public void event(final JSONObject json, final UniJSCallback callback) {
        String method = json.getString("method");
        Object data = true;
        try {
            JSONObject param = json.getJSONObject("param");
            if (param == null)
                param = new JSONObject();
            if (_callback == null)
                _callback = callback;
            switch (method) {
                case "isConnected"://是否已连接
                    data = isConnected();
                    break;
                case "connect"://连接
                    connect(param);
                    data = SERVER_HOST + ":" + SERVER_PORT;
                    _callback = callback;
                    break;
                case "send"://发送消息
                    send(param);
                    return;
                case "close"://关闭
                    close();
                    break;
            }
            callBack(Res.returnSuccess(method, data));
            switch (method) {
                case "close":
                    _callback = null;
                    break;
            }
        } catch (Exception e) {
            callBack(Res.returnError(method, e));
        } catch (Throwable e) {
            callBack(Res.returnError(method, e));
        }
    }

    public boolean isConnected() {
        try {
            if (socket == null || socket.isClosed()) {
                return false;
            } else {
                return socket.isConnected();
            }
        } catch (Exception ex) {
            return false;
        }
    }

    public void connect(JSONObject param) throws IOException {
        try {
            Params.initParams(param);
        } catch (Exception e) {
            callBack(Res.returnError("connect", e));
        }
        SERVER_HOST = param.getString("ip");
        SERVER_PORT = param.getInteger("port");

        if (SERVER_HOST == null || "".equals(SERVER_HOST)) {
            throw new BadRequestException("缺少参数ip");
        }
        if (SERVER_PORT == 0) {
            throw new BadRequestException("参数port必须大于0");
        }

        if (isConnected()) {
            throw new BadRequestException("客户端已连接，不能重复连接。");
        }

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    // 创建socket
                    socket = new Socket(SERVER_HOST, SERVER_PORT);

                    // 创建IO流
                    reader = new DataInputStream(socket.getInputStream());
                    outputStream = socket.getOutputStream();
                    writer = new BufferedWriter(
                            new OutputStreamWriter(outputStream, Params.charset)
                    );

                    while (socket != null) {
                        try {
                            if (Params.hexMsg) {
                                String msgStr = hexMsg + HexUtil.readInputStream(reader);
                                msgStr = msgStr.toUpperCase();
                                if (Params.isCheck) {
                                    receiveToVue("msgStr", msgStr);
                                    continue;
                                }
                                hexMsg = "";
                                //粘包闭包处理，最后一个元素是未接收完成的数据
                                List<String> msgArray = HexUtil.glue(msgStr);
                                for (int i = 0; i < msgArray.size(); i++) {
                                    if (i == msgArray.size() - 1) {
                                        //计算长度
                                        hexMsg += msgArray.get(i);
                                    } else {
                                        receiveToVue("receive", msgArray.get(i));
                                    }
                                }
                                continue;
                            }
                            byte[] buffer;
                            buffer = new byte[reader.available()];
                            if (buffer.length != 0) {
                                // 读取缓冲区
                                reader.read(buffer);
                                String msg = new String(buffer, Params.charset);//注意转码，不然中文会乱码。
                                receiveToVue("receive", msg);
                            }
                        } catch (Exception ex) {

                        }
                    }

                } catch (IOException e) {
                    callBack(Res.returnError("connect", e));
                } finally {
                }
            }
        }).start();
    }

    private void receiveToVue(String method, Object data) throws InterruptedException {
        if (Params.receiveDelayMs > 0) {
            Thread.sleep(Params.receiveDelayMs);
        }
        callBack(Res.sendSuccess(method, data));
    }


    public void send(JSONObject param) throws IOException {
        final String message = param.getString("message");
        if (message == null || "".equals(message)) {
            throw new BadRequestException("缺少参数message");
        }

        if (!isConnected()) {
            throw new BadRequestException("客户端未连接");
        }

        new Thread(new Runnable() {
            @Override
            public void run() {
                // 发送消息给服务器
                try {
                    if (Params.hexMsg) {
                        byte[] bytes = HexUtil.hexStringToByteArray(message);
                        outputStream.write(bytes);
                        outputStream.flush();
                    } else {
                        writer.write(message + "\n");
                        writer.flush();
                    }
                    callBack(Res.returnSuccess("send", message));
                } catch (IOException e) {
                    callBack(Res.returnError("send", e));
                }
            }
        }).start();

    }

    public void close() throws IOException {
        try {
            writer.close(); //关闭之前还会flush一次
        } catch (Exception exception) {

        }
        try {
            socket.close();
        } catch (Exception exception) {

        }
        try {
            reader.close();
            socket = null;
        } catch (Exception exception) {

        }
    }

    public void callBack(Object data) {
        if (_callback != null) {
            _callback.invokeAndKeepAlive(data);
        }
    }

}

